package cn.liip.util;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

import org.bson.types.ObjectId;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.MongoClient;
import com.mongodb.MongoException;
import com.mongodb.QueryOperators;
import com.mongodb.util.JSON;
/**  
 *   
 * <b>功能：实现MongoDB的CRUD操作</b><br>   
 * <br>
 * <b>创建日期：</b> 2013-09-18 上午10:58:56 <br>  
 * @author 罗林
 * @version 1.0  
 */ 
public class MongoDBUtil {
//  private static final String URL="222.197.200.122";//连接地址  
  private static final String URL=ConfigUtil.getProperty("mongoIp");//连接地址  

    private static final int PORT=27017;//连接端口  
    private static final String DB=ConfigUtil.getProperty("database");//连接DB  
  
    private static MongoClient mg = null;  
    private static DB db=null;  
    private DBCollection conn=null;  
		/**
		 * <b>功能：单例模式</b><br>
		 * <b>提示:在这里DB理解为数据库,DBCollection理解为表</b><br>
		 * <br>
		 * @author 罗林
		 * @return DB 返回数据库
		 */
		private static synchronized DB getDb(){
			 try {  
		            if(db==null){  
		                mg = new MongoClient(URL, PORT);  
		                //获取 DB；如果默认没有创建，mongodb会自动创建  
		                db = mg.getDB(DB);  
//		                db.authenticate(ConfigUtil.getProperty("db_username"), ConfigUtil.getProperty("db_password").toCharArray());
		            }  
		        } catch (Exception e) {  
		            e.printStackTrace();  
		        }   
		        return db;  
		}

		/**
		 * 
		 * <b>功能：获取连接</b><br>
		 * <br>
		 * @修改者 罗林, 2013-09-18
		 * @param connName 表连接名称
		 * @return DBCollection 表连接对象
		 */
		public DBCollection  getConn(String connName){
			getDb();
			return db.getCollection(connName);
		}

		/**
		 * 
		 * <b>功能：对象销毁，清除内存</b><br>
		 * <br>
		 * @修改者  罗林, 2013-09-18
		 */
		public void destory() {			
			  if (mg != null)  
		            mg.close();  
		        mg = null;  
		        db = null;  
		        conn = null;  
		        System.gc(); //进行垃圾回收
		}

		/**
		 * 
		 * <b>功能：根据Mongo对象条件查询所有数据</b><br>
		 * <br>
		 * @修改者  罗林, 2013-09-18
		 * @param dbObject Mongo条件对象
		 * @param connName 表连接名称
		 * @param className 获取对象的类名称
		 * @return
		 * @throws Exception List 返回集合
		 */
		public List<Object> findAll(DBObject dbObject,String connName,String className)throws Exception{
			List<Object> resultList=new ArrayList<Object>();
			try {
				conn=getConn(connName);
				
				List<DBObject> list = conn.find(dbObject).toArray();
				for(DBObject dbObj:list){
					dbObj.put("_id", dbObj.get("_id").toString());
					Object obj= DB2Bean(dbObj,className);
					resultList.add(obj);
				}
			} catch (Exception e) {
				e.printStackTrace();
				throw new Exception();
			}finally{
				//destory();
			}
			return resultList;
		}
		/**
		 * 
		 * <b>功能：根据Mongo对象条件查询所有数据</b><br>
		 * <br>
		 * @修改者  罗林, 2013-09-18
		 * @param dbObject Mongo条件对象
		 * @param connName 表连接名称
		 * @param className 获取对象的类名称
		 * @return
		 * @throws Exception List 返回集合
		 */
		public List findAllList(DBObject dbObject,String connName,String className)throws Exception{
			List<Object> resultList=new ArrayList<Object>();
			try {
				conn=getConn(connName);
				
				List<DBObject> list = conn.find(dbObject).toArray();
				for(DBObject dbObj:list){
					dbObj.put("_id", dbObj.get("_id").toString());
					Object obj= DB2Bean(dbObj,className);
					resultList.add(obj);
				}
			} catch (Exception e) {
				e.printStackTrace();
				throw new Exception();
			}finally{
				//destory();
			}
			return resultList;
		}
		
		/**
		 * 
		 * <b>功能：根据自定义对象条件查询所有数据</b><br>
		 * <br>
		 * @修改者  罗林, 2013-09-18
		 * @param object 定义条件对象
		 * @param connName 表连接名称
		 * @param className 获取对象的类名称
		 * @return
		 * @throws Exception List 返回集合
		 */
		public List<Object> findAll(Object object,String connName,String className)throws Exception{
			List<Object> resultList=new ArrayList<Object>();
			try {
				conn=getConn(connName);
				List<DBObject> list = conn.find(bean2DB(object)).toArray();
				for(DBObject dbObj:list){
					Object obj= DB2Bean(dbObj,className);
					resultList.add(obj);
				}
			} catch (Exception e) {
				e.printStackTrace();
				throw new Exception();
			}finally{
				destory();
			}
			return resultList;
		}
		
		
		
		public List<Object> findBean(DBObject object,String connName,String className)throws Exception{
			List<Object> resultList=new ArrayList<Object>();
			try {
				conn=getConn(connName);
				DBCursor cur = conn.find(object);
				while(cur.hasNext()){
					Object obj= DB2Bean(cur.next(),className);
					resultList.add(obj);
				}
			} catch (Exception e) {
				e.printStackTrace();
				throw new Exception();
			}finally{
				destory();
			}
			return resultList;
		}		
		/**
		 * 
		 * <b>功能：根据自定义对象条件查询不同数据</b><br>
		 * <br>
		 * @param  field需要返回结果的字段
		 * @param  connName 表连接名称
		 * @param  keyword 查询条件
		 * @return
		 * @throws Exception List 返回集合
		 */		
		@SuppressWarnings("unchecked")
		public List<Object> findDistinct(String field,String keyword,String historyFlag,String connName)throws Exception{
			List<Object> resultList=new ArrayList<Object>();
			try {
				conn=getConn(connName);
				DBObject obj = new BasicDBObject();	
				obj.put("keyword", keyword);
				obj.put("historyFlag", historyFlag);
				resultList = conn.distinct(field,obj);
			} catch (Exception e) {
				e.printStackTrace();
				throw new Exception();
			}finally{
				destory();
			}
			return resultList;
		}
		
		/**
		 * 
		 * <b>功能：话题分页</b><br>
		 * <br>
		 * @param  field需要返回结果的字段
		 * @param  connName 表连接名称
		 * @param  keyword 查询条件
		 * @return
		 * @throws Exception List 返回集合
		 */		
		@SuppressWarnings("unchecked")
		public List<Object> findTopicPager(String field,String keyword,String historyFlag,String connName,int offset,int pagelength)throws Exception{
			List<Object> resultList=new ArrayList<Object>();
			List<Object> totalList=new ArrayList<Object>();
			try {
				conn=getConn(connName);
				DBObject obj = new BasicDBObject();	
				obj.put("keyword", keyword);
				obj.put("historyFlag", historyFlag);
				totalList = conn.distinct(field,obj);
				for(int i = 0;i<pagelength && offset<totalList.size()-1 ;i++){
					resultList.add(totalList.get(++offset));
				}
			} catch (Exception e) {
				e.printStackTrace();
				throw new Exception();
			}finally{
				destory();
			}
			return resultList;
		}			
		
		
		/**
		 * 
		 * <b>功能：根据自定义对象条件查询前N条数据</b><br>
		 * <br>
		 * @修改者  罗林, 2013-09-18
		 * @param object 定义条件对象
		 * @param connName 表连接名称
		 * @param className 获取对象的类名称
		 * @return
		 * @throws Exception List 返回集合
		 */
		@SuppressWarnings("unchecked")
		public List<Object> findLimitOrderByTime(String connName,String className)throws Exception{
			List<Object> resultList=new ArrayList<Object>();
			try {
				conn=getConn(connName);
				
				DBObject dbObj = null;
					DBObject value = (DBObject) JSON.parse( String.format("{ indexFlag_tem:{$exists: %s}}", false));
					DBObject valueSort = (DBObject) JSON.parse( String.format("{timeStamp:%s}", -1));
					DBCursor dbCursor =  conn.find(value);
					
					dbCursor.sort(valueSort).limit(1000);				
					while(dbCursor.hasNext()){
						
						dbObj= dbCursor.next();
						dbObj.put("_id", dbObj.get("_id").toString());
						Object obj= DB2Bean(dbObj,className);//
						resultList.add(obj);//
					}
			} catch (Exception e) {
				e.printStackTrace();
				throw new Exception();
			}finally{
				destory();
			}
			return resultList;
		}

		/**
		 * 
		 * <b>功能：根据Mongo对象查询单个数据</b><br>
		 * <br>
		 * @修改者 罗林, 2013-09-18
		 * @param dbObject   Mongo条件对象
		 * @param connName 表连接名称
		 * @param className 获取对象的类名称
		 * @return 
		 * @throws Exception Object 返回对象
		 */
		public Object findOne(DBObject dbObject,String connName,String className)throws Exception{
			Object obj=null;
			try {
				conn=getConn(connName);
				DBObject result = conn.findOne(dbObject);
				result.put("_id", result.get("_id").toString());
				obj=DB2Bean(result, className);
			} catch (Exception e) {
				e.printStackTrace();
				throw new Exception();
			}finally{
				//destory();
			}
			return obj;
		}
	
		
		/**
		 * 
		 * <b>功能：根据自定义对象查询单个数据</b><br>
		 * <br>
		 * @修改者  罗林, 2013-09-18
		 * @param object   自定义条件对象
		 * @param connName 表连接名称
		 * @param className 获取对象的类名称
		 * @return
		 * @throws Exception Object 返回对象
		 */
		public Object findOne(Object object,String connName,String className)throws Exception{
			Object obj=null;
			try {
				conn=getConn(connName);
				DBObject result = conn.findOne(bean2DB(object));
				obj=DB2Bean(result, className);
			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				//destory();
			}
			return obj;
		}
		
		/**
		 * 
		 * <b>功能：根据条件id查询数据</b><br>
		 * <br>
		 * @修改者  罗林, 2013-09-18
		 * @param id 条件id
		 * @param connName  表连接名称
		 * @param className 获取对象的类名称
		 * @return
		 * @throws Exception Object 返回对象
		 */
		public Object findOneById(Object id,String connName,String className)throws Exception{
			Object obj=null;
			try {
				conn=getConn(connName);
				DBObject dbObject = conn.findOne(new BasicDBObject("_id",id));
				obj=DB2Bean(dbObject, className);
			} catch (Exception e) {
				e.printStackTrace();
				throw new Exception();
			}finally{
				//destory();
			}
			return obj;
		}

		
		/**
		 * 
		 * <b>功能：增加数据</b><br>
		 * <br>
		 * @修改者  罗林, 2013-09-18
		 * @param dbObject 封装对象的数据
		 * @param connName  表连接名称
		 * @return
		 * @throws Exception int  返回影响结果
		 */
		public int add(DBObject dbObject,String connName)throws Exception{
			int result=-1;
			try {
				conn=getConn(connName);
				result=conn.insert(dbObject).getN();
			} catch (Exception e) {
				e.printStackTrace();
				throw new Exception();
			}finally{
//				destory();
			}
			return result;
		}

		/**
		 * 
		 * <b>功能：修改数据</b><br>
		 * <br>
		 * @修改者  罗林, 2013-09-18
		 * @param value 修改的数据
		 * @param where 修改条件
		 * @param connName  表连接名称
		 * @return
		 * @throws Exception int 返回影响结果
		 */
		public int update(DBObject value,DBObject where,String connName) throws Exception{
			int result=-1;
			try {
				conn=getConn(connName);
				result= conn.update(where, value,false,true).getN();
			} catch (MongoException e) {
				e.printStackTrace();
				throw new Exception();
			}finally{
				//destory();
			}
			return result;
		}
		/**
		 * 
		 * <b>功能：修改数据</b><br>
		 * <br>
		 * @修改者  罗林, 2013-09-18
		 * @param value 修改的数据
		 * @param where 修改条件
		 * @param connName  表连接名称
		 * @return
		 * @throws Exception int 返回影响结果
		 */
		public int update(BasicDBObject value,DBObject where,String connName) throws Exception{
			int result=-1;
			try {
				conn=getConn(connName);
				DBObject dbValue = new BasicDBObject();
				dbValue.put("$set", value);
				result= conn.update(where, value,false,true).getN();
			} catch (MongoException e) {
				e.printStackTrace();
				throw new Exception();
			}finally{
				//destory();
			}
			return result;
		}

		/**
		 * 
		 * <b>功能：修改数据</b><br>
		 * <br>
		 * @修改者  罗林, 2013-09-18
		 * @param value 修改的数据
		 * @param where 修改条件
		 * @param connName  表连接名称
		 * @return
		 * @throws Exception int 返回影响结果
		 */
		public int update(Object value,Object where,String connName)throws Exception {
			int result=-1;
			try {
				conn=getConn(connName);
//				LogUtil.info(bean2DB(where));
//				LogUtil.info(bean2DB(value));
				result= conn.update(bean2DB(value),bean2DB(where)).getN();
			} catch (MongoException e) {
				e.printStackTrace();
				throw new Exception();
			}finally{
				//destory();
			}
			return result;
		}
		/**
		 * 
		 * <b>功能：根据id 查询一条数据并设置其  indexFlag 属性为 true</b><br>
		 * <br>
		 * @param latest 要查询的 _id信息
		 * @param connName  表连接名称
		 * @return int 
		 * @throws Exception int 返回影响结果
		 * 
		 * 
		 */
		public int setIndexFlag_true(DBObject latest,String connName)throws Exception {
			int result=-1;
			try {
				conn=getConn(connName);
				DBObject value = (DBObject) JSON.parse( String.format("{ $set:{indexFlag: %s}}", true));				
				result=conn.update(latest,value).getN();
			} catch (MongoException e) {
				e.printStackTrace();
				throw new Exception();
			}finally{
				//destory();
			}
			return result;
		}
		/**
		 * 
		 * <b>功能：数据里增加一个属性</b><br>
		 * <br>
		 * @param latest 要查询的 _id信息
		 * @param connName  表连接名称
		 * @return int 
		 * @throws Exception int 返回影响结果
		 * 
		 * 
		 */
		public int insertIndexFlag_tem(DBObject latest,String connName)throws Exception {
			int result=-1;
			try {
				conn=getConn(connName);
				DBObject value = (DBObject) JSON.parse( String.format("{ $set:{indexFlag_tem: %s}}", true));				
				result=conn.update(latest,value).getN();
			} catch (MongoException e) {
				e.printStackTrace();
				throw new Exception();
			}finally{
				//destory();
			}
			return result;
		}
		
	
		/**
		 * 
		 * <b>功能：根据条件删除数据</b><br>
		 * <br>
		 * @修改者  罗林, 2013-09-18
		 * @param obj 要删除的对象
		 * @param connName 表连接名称
		 * @return
		 * @throws Exception int 返回影响结果
		 */
		public int remove(Object obj,String connName) throws Exception{
			int result=-1;
			try {
				conn=getConn(connName);
				result= conn.remove(bean2DB(obj)).getN();
			} catch (MongoException e) {
				e.printStackTrace();
				throw new Exception();
			}finally{
				//destory();
			}
			return result;
		}
		
		/**
		 * 
		 * <b>功能：根据条件删除数据</b><br>
		 * <br>
		 * @修改者  罗林, 2013-09-18
		 * @param dbObject  要删除的数据
		 * @param connName 表连接名称
		 * @return
		 * @throws Exception int 返回影响结果
		 */
		public int remove(DBObject dbObject,String connName)throws Exception {
			int result=-1;
			try {
				conn=getConn(connName);
				result= conn.remove(dbObject).getN();
			} catch (MongoException e) {
				e.printStackTrace();
				throw new Exception();
			}finally{
				//destory();
			}
			return result;
		}
		
		/**
		 * 
		 * <b>功能：根据条件得到数据总和</b><br>
		 * <br>
		 * @修改者  罗林, 2013-09-18
		 * @param dbObject 条件对象
		 * @param connName  表连接名称
		 * @return
		 * @throws Exception int 返回影响结果
		 */
		public int getCount(DBObject dbObject,String connName)throws Exception{
			int result=0;
			try {
				conn=getConn(connName);
				result=conn.find(dbObject).count();
			} catch (Exception e) {
				e.printStackTrace();
				throw new Exception();
			}
			return result;
		}
		
		/**
		 * 
		 * <b>功能：根据条件得到数据总和</b><br>
		 * <br>
		 * @修改者  罗林, 2013-09-18
		 * @param obj 条件对象
		 * @param connName 表连接名称
		 * @return
		 * @throws Exception int 返回影响结果
		 */
		public int getCount(Object obj,String connName)throws Exception{
			int result=0;
			try {
				conn=getConn(connName);
				result=conn.find(bean2DB(obj)).count();
			} catch (Exception e) {
				e.printStackTrace();
			}
			return result;
		}
		
		/**
		 * 
		 * <b>功能：判定表中是否存在</b><br>
		 * <br>
		 * @修改者  罗林, 2013-09-18
		 * @param obj 条件对象
		 * @param connName 表连接名称
		 * @return boolean
		 * @throws Exception Object
		 */
		public boolean isExist(Object obj,String connName){
			if(obj instanceof DBObject)//判定obj是否是DBObject类型数据
			{
				DBObject dbObject = (DBObject)obj;
				conn=getConn(connName);
				if(conn.findOne(dbObject) != null){
					return true;
				}
			}
			return false;
		}
		
		/**
		 * 
		 * <b>功能：将自定义对象转换为Mongo对象</b><br>
		 * <br>
		 * @修改者  罗林, 2013-09-18
		 * @param obj 自定义对象
		 * @return DBObject Mongo对象
		 */
		public static DBObject bean2DB(Object obj)throws Exception{
			DBObject dbObject=new BasicDBObject();
			Class<? extends Object> clazz=obj.getClass();
			Field [] fields=clazz.getDeclaredFields();
			for(Field field:fields){
				String fieldName=field.getName();
				String methodName="get"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1,fieldName.length());
				Method method=null;
				Object  resultObj=null;
				try {
					method=clazz.getMethod(methodName);
				} catch (Exception e) {
					e.printStackTrace();
					continue;
				}
				try {
					resultObj=method.invoke(obj);
				} catch (Exception e) {
					continue;
				}
				if(resultObj!=null&&!resultObj.equals("")){
					dbObject.put(fieldName, resultObj);
				}
			}
			return dbObject;
		}
		
		/**
		 * 
		 * <b>功能：将Mongo对象转换为自定义对象</b><br>
		 * <br>
		 * @修改者  罗林, 2013-09-18
		 * @param dbObject Mongo对象
		 * @param className 要转换的类名称
		 * @return
		 * @throws Exception Object
		 */
		public static Object DB2Bean(DBObject dbObject,String className) throws Exception{
			Class clazz=Class.forName(className);
			Object obj=clazz.newInstance();
			Field [] fields=clazz.getDeclaredFields();
			for(Field field:fields){
				String fieldName=field.getName();
				String methodName="set"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1,fieldName.length());
				Method method=null;
				Object  resultObj=null;
				try {
					method=clazz.getMethod(methodName,new Class[]{field.getType()});
				} catch (Exception e) {
					e.printStackTrace();
					continue;
				}
				resultObj=dbObject.get(fieldName);
				try {
					resultObj=method.invoke(obj,new Object[]{resultObj});
				} catch (Exception e) {
					continue;
				}
			}
			return obj;
		}
		/**
		 * 
		 * <b>功能：根据自定义对象条件查询不同数据</b><br>
		 * <br>
		 * @param  type 01：新闻；02：微博
		 * @param  connName 表连接名称
		 * @param  keyword 查询条件
		 * @return
		 * @throws Exception List 返回集合
		 */		
		@SuppressWarnings("unchecked")
		public List<String> findZhData(String type,String url,String connName)throws Exception{
			List<String> resultList=new ArrayList<String>();
			try {
				conn=getConn(connName);
				DBObject obj = new BasicDBObject();	
				obj.put("collectionUrl", url);
				resultList = conn.distinct(type,obj);
			} catch (Exception e) {
				e.printStackTrace();
				throw new Exception();
			}finally{
				destory();
			}
			return resultList;
		}	

}
